package cn.wolfcode.service.impl;

import cn.wolfcode.service.IDocumentService;
import org.springframework.ai.document.Document;
import org.springframework.ai.reader.tika.TikaDocumentReader;
import org.springframework.ai.transformer.splitter.TokenTextSplitter;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import reactor.core.publisher.Mono;

import java.util.List;

@Service
public class DocumentServiceImpl implements IDocumentService {

    // 从 Spring 容器中拿到我们配置的向量数据库
    @Autowired
    private VectorStore vectorStore;

    /**
     * 需要做的事情
     *  1. 向向量数据库中存储我们上传文件的内容。
     *
     *  2. 给前端返回 文件名   上传成功/上传失败
     */
    @Override
    public Mono<String> upload(List<MultipartFile> files) {
        // 这里文件上传可能会出现异常。所以我们专门开辟一条线程来处理向向量数据库中存储数据的过程。
        //  Mono.fromCallable(); 方法开辟线程。并用于将一个 Callable 对象转换为一个 Mono 对象，
        //  并返回其结果或异常。
        // () -> {}  JDK8 新特性。 Lambda 表达式  () 参数  {} 需要做的事情。
        Mono<String> mono = Mono.fromCallable(() -> {
            // 验证传入进来的文件不能为 Null
            if(files == null){
                return null;
            }
            // 构建 StringBuilder . 他更适合做字符串拼接
            StringBuilder result = new StringBuilder();
            // 若不为 Null 则遍历文件集合拿到每一个文件
            for(MultipartFile file : files){
                // 判断每个文件是否为 Null，若当前文件为 Null 则跳出当前循环即可。执行下一次循环。
                if(file.isEmpty()){
                    continue;   // 结束本次循环，继续下次循环。
                }
                // 获取文件的名字
                String fileName = file.getOriginalFilename();
                // 获取文件资源
                Resource resource = file.getResource();
                // 我们需要处理文件的资源，将其从不同格式中提取文本内容，然后做同一分词处理。
                // 那我们就需要使用到 SpringAI 框架中的 TiKa 框架。
                // TiKa 框架就是对文档内容进行读取分词的。构建对象时将我们文件资源读取到 TiKa 框架中
                TikaDocumentReader documentReader = new TikaDocumentReader(resource);
                // 需要将 TiKa 框架中的内容读取出来。读取成为 Document 格式。（转换为 Document 格式）
                List<Document> list = documentReader.read();
                // 对 documentList 文档集合对象进行切分。
                // 想切分就需要使用工具。创建一个切分工具
                TokenTextSplitter tokenTextSplitter = TokenTextSplitter.builder()
                        .withKeepSeparator(true)    // 保留标点符号
                        .withChunkSize(1000)        // 切分后的 token 数量。
                        .build();                   // 构建该切分工具。

                // 使用我们构建好的切分工具按照我们设置的规则对 documentList 进行切分
                List<Document> documentList = tokenTextSplitter.split(list);
                // 将文档内容存储到向量数据库中。
                vectorStore.add(documentList);

                // 2. 准备向前端展示数据
                // .append 相当于 +  拼接字符串   文件名   上传成功
                result.append(fileName).append("   ").append("上传成功\n");
            }
            // 将其改编为字符串格式
            return result.toString();
        });
        return mono;
    }
}